package com.ruoyi.course.domain.vo;

import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.CourseClassInfo;
import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.SchedulingData;
import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.TimeSlot;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * MCTS算法中的动作类，表示为某个课程班分配特定的时间、教师和教室
 */
public class MctsAction {
    private String courseClassId;  // 课程班ID
    private String teacherId;      // 教师ID
    private String classroomId;    // 教室ID
    private List<TimeSlot> timeSlots;  // 时间段列表（支持多时间槽组合）
    private SchedulingData schedulingData;  // 排课基础数据引用

    // 构造函数：接收必要的排课信息
    public MctsAction(String courseClassId, String teacherId, String classroomId,
                      List<TimeSlot> timeSlots, SchedulingData schedulingData) {
        this.courseClassId = courseClassId;
        this.teacherId = teacherId;
        this.classroomId = classroomId;
        this.timeSlots = timeSlots;
        this.schedulingData = schedulingData;
    }

    // 简化构造函数（用于不需要完整描述的场景）
    public MctsAction(String courseClassId, String teacherId, String classroomId, List<TimeSlot> timeSlots) {
        this(courseClassId, teacherId, classroomId, timeSlots, null);
    }

    /**
     * 获取完整的动作描述（包含课程信息和周范围）
     */
    public String getActionDesc() {
        // 格式化时间槽信息
        String timeDesc = formatTimeSlotsWithWeekInfo();

        return String.format("课程班[%s] -> 教师[%s] 教室[%s] 时间[%s]",
                courseClassId, teacherId, classroomId, timeDesc);
    }

    /**
     * 格式化时间槽列表，包含周范围信息
     */
    private String formatTimeSlotsWithWeekInfo() {
        // 如果没有排课数据，直接使用基础时间格式
        if (schedulingData == null) {
            return formatBasicTimeSlots();
        }

        // 获取课程信息以获取周范围
        CourseClassInfo course = schedulingData.getCourseClasses().get(courseClassId);
        if (course == null) {
            return formatBasicTimeSlots();
        }

        // 使用包含周范围的完整格式
        return timeSlots.stream()
                .map(slot -> slot.toFullString(course.getStartWeek(), course.getEndWeek()))
                .collect(Collectors.joining("; "));
    }

    /**
     * 基础时间槽格式化（不包含周范围）
     */
    private String formatBasicTimeSlots() {
        return timeSlots.stream()
                .map(TimeSlot::toString)
                .collect(Collectors.joining("; "));
    }

    // Getters and Setters
    public String getCourseClassId() {
        return courseClassId;
    }

    public void setCourseClassId(String courseClassId) {
        this.courseClassId = courseClassId;
    }

    public String getTeacherId() {
        return teacherId;
    }

    public void setTeacherId(String teacherId) {
        this.teacherId = teacherId;
    }

    public String getClassroomId() {
        return classroomId;
    }

    public void setClassroomId(String classroomId) {
        this.classroomId = classroomId;
    }

    public List<TimeSlot> getTimeSlots() {
        return timeSlots;
    }

    public void setTimeSlots(List<TimeSlot> timeSlots) {
        this.timeSlots = timeSlots;
    }

    public SchedulingData getSchedulingData() {
        return schedulingData;
    }

    public void setSchedulingData(SchedulingData schedulingData) {
        this.schedulingData = schedulingData;
    }

    /**
     * 重写equals：确保相同的排课方案被视为同一动作
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MctsAction that = (MctsAction) o;
        return Objects.equals(courseClassId, that.courseClassId) &&
                Objects.equals(teacherId, that.teacherId) &&
                Objects.equals(classroomId, that.classroomId) &&
                Objects.equals(timeSlots, that.timeSlots);
    }

    /**
     * 重写hashCode：与equals保持一致
     */
    @Override
    public int hashCode() {
        return Objects.hash(courseClassId, teacherId, classroomId, timeSlots);
    }

    /**
     * 重写toString：显示简洁的动作信息
     */
    @Override
    public String toString() {
        return getActionDesc();
    }
}
